<template>
  <div class="flex-row serviceContainer">

    <service-list v-if="showServiceList"></service-list>
    <div class="layui-tab layui-tab-brief flex-column chat-column" style="backgroundColor:#e6e6e6" lay-filter="changeTab">
      <ul class="flex-row layui-tab-title">
        <li class="layui-this" lay-id="message">消息</li>
        <li lay-id="addressbook">通讯录</li>
      </ul>
     <div class="layui-tab-content autoGrow">
      <div class="layui-tab-item layui-show">
        <chat-list
          :showServiceList="showServiceList"
          @toggleServiceList="toggleServiceList">
        </chat-list>
      </div>
      <div class="layui-tab-item" style="height: 100%; overflow: auto;">
        <div class="chatOperate flex-row">
          <el-input
            class="chat-filter-input"
            placeholder="关键词过滤"
            size="mini"
            v-model="friendFilterWord"
            prefix-icon="el-icon-search"
            clearable>
          </el-input>
        </div>

        <button @click="accountSync" style="margin: 0 auto; display: block;" type="button" class="layui-btn">
          同步通讯录
          <i v-if="accoutsyncing" class="layui-icon layui-icon-loading-1 layui-anim layui-anim-rotate layui-anim-loop"></i>
        </button>
        <el-collapse class="contacts-list" v-model ="showCollapse">
          <el-collapse-item name="group" v-if="groupFilterList&&groupFilterList.length">
            <div slot="title" class="list-title">群聊</div>
            <div v-for="(item) in groupFilterList" :key="item.id" @click.stop="showGroupInfo(item)" :class="['contacts-list-item',item.groupno === currentFriend.groupno?'active':'']">
              <group
                :avatar="item.avatar"
                :name="item.groupname"
                :member="item.personnum"
                :friend="item.friendNum"
              />
            </div>

          </el-collapse-item>

          <el-collapse-item name="user" v-if="friendListMap[uistate.accountid]&&friendListMap[uistate.accountid].length">
            <div slot="title" class="list-title">好友</div>
            <div v-for="(item) in friendFilterList" :key="item" @click.stop="showFriendInfo(friendMap[item])" :class="['contacts-list-item',item === currentFriend.id?'active':'']">
              <friend
                :avatar="(friendMap[item]||{}).avatar"
                :name="(friendMap[item]||{}).friendnick"
                :gender="(friendMap[item]||{}).friendsex"
                />
            </div>
          </el-collapse-item>
        </el-collapse>

        <!-- <div v-else class="flex-column autoGrow" style="justify-content: center;align-items: center;height:100%">
          <i class="layui-icon layui-icon-face-cry" style="font-size:32px;color:#FF5722"></i>
          <div style="margin-top:10px;color:#999">暂无数据</div>
        </div> -->
      </div>

      </div>
    </div>
    <div class="userDetail flex-row autoGrow" v-if="tab==='addressBook'">

      <div v-if="currentFriend.friendwxid" class="flex-column">

        <div class="profile flex-row" v-if="currentFriend.friendwxid">
          <div>
            <span>{{currentFriend.friendnick}}</span>
            <img src="../assets/images/male.png" class="userGender" v-if="currentFriend.friendsex === 1">
            <img src="../assets/images/female.png" class="userGender" v-else-if="currentFriend.friendsex === 2">
          </div>
          <img :src="currentFriend.avatar" class="userAvatar" alt="">
        </div>
        <div class="detail flex-column" v-if="currentFriend.friendwxid">
          <div>
            <span class="fontGrey">备注</span>
            <span>{{currentFriend.friendnick || ''}}</span>
          </div>
          <div>
            <span class="fontGrey">微信号</span>
            <span>{{currentFriend.friendalias||currentFriend.friendwxid || ''}}</span>
          </div>
          <div v-if="friendDetail.vipInfo">
              <div>
                <span class="fontGrey label-width">App账号ID</span>
                <span>{{ friendDetail.vipInfo.userId || '' }}</span>
              </div>
              <div>
                <span class="fontGrey label-width">生日</span>
                <span>{{friendDetail.vipInfo.birth|| '' }}</span>
              </div>
              <div>
                <span class="fontGrey label-width">会员类型</span>
                <span>{{friendDetail.vipInfo.vipProdName || ''}}</span>
              </div>
              <div>
                <span class="fontGrey label-width">会员到期时间</span>
                <span>{{friendDetail.vipInfo.vipEndDate|| ''}}</span>
              </div>
              <div>
                <span class="fontGrey label-width">最近一次消费时间</span>
                <span>{{friendDetail.vipInfo.lastBuyTime || ''}}</span>
              </div>
              <div>
                <span class="fontGrey label-width">会员消费总金额</span>
                <span>{{friendDetail.vipInfo.vipBuyAmount|| ''}}元</span>
              </div>
              <div>
                <span class="fontGrey label-width">充值消费总金额</span>
                <span>{{friendDetail.vipInfo.vcoinBuyAmount || ''}}元</span>
              </div>
              <div>
                <span class="fontGrey label-width">近一个月消费频次</span>
                <span>{{friendDetail.vipInfo.payNum30|| ''}}</span>
              </div>
          </div>

        </div>

        <button class="sendMessage layui-btn layui-btn-normal" @click="addChat(currentFriend)">{{currentFriend.friendwxid?'发消息':'进入群聊'}}</button>

      </div>
      <div class="flex-column vip-group" v-if="currentFriend.friendwxid && friendDetail.groups">
          <div class="caption">
            <div class="title">
              <span>用户所在群</span>
              <el-button @click="openInviteDialog({ csid:currentFriend.csid,wxaccount:currentFriend.wxaccount,friendwxid:(currentFriend.friendalias||currentFriend.friendwxid) })" class="btn-add-group" type="primary" icon="el-icon-plus" size="mini" round>邀请进群</el-button>
            </div>
            <div class="th flex-row">
              <div class="td vip-group-name">群名</div>
              <div class="td vip-group-isvip ">会员群</div>
              <div class="td vip-group-ctrl ">操作</div>
            </div>
          </div>
          <div class="vip-group-scroll">
            <div class="tr" v-for="(gro) in friendDetail.groups" :key="gro.id">

              <div class="td vip-group-name" :title="gro.groupno|| ''">{{gro.groupname|| ''}}({{gro.groupno|| ''}})</div>
              <div class="td vip-group-isvip">{{ (gro.groupname||'').indexOf('会员')>-1?'是':'否' }}</div>
              <div class="td vip-group-ctrl">
                <el-button type="primary" @click="deleteUser({ csid:currentFriend.csid,wxaccount:currentFriend.wxaccount,friendwxid:gro.groupno,realFromNick:currentFriend.friendnick,realFromWxId:(currentFriend.friendalias||currentFriend.friendwxid) })" size="mini" round>移出群</el-button>
              </div>

            </div>
          </div>
      </div>

      <groupProfile
        v-if="currentFriend && currentFriend.groupno"
        :csid="currentFriend.csid"
        :groupno="currentFriend.groupno"
        :wxaccount="currentFriend.wxaccount"
        :account="account"
        :backChatHandler="()=>$element.tabChange('changeTab', 'message')"
      />

    </div>
    <div @drop.prevent="fileDrop" @dragenter.prevent @dragover.prevent @dragleave.prevent class="chatContainer flex-column" v-if="tab==='messageList'">
      <div class="messageTitle listTitle flex-row">
        <slot v-if="chatMap[uistate.chatid] ">
          <div>
            <span>{{ isGroup?(chat.friendNick||'群聊天'):chat.friendNick }}</span>
            <span v-if="!isGroup" class="setVip pointer" @click="changeUserVip(true)">
              {{ chatMap[uistate.chatid].isTop == 2?'取消VIP':'设为VIP用户' }}
            </span>

          </div>
          <div style="display:flex;flex-direction:row;align-items:center">
            <div class="shieldMessage pointer" @click="toggleMessageDecline" v-if="chatMap[uistate.chatid].isTop !== 2">
              {{chatMap[uistate.chatid].showstatus ? '取消屏蔽' : '屏蔽消息'}}
            </div>
            <el-tooltip v-if="isGroup" class="item" effect="dark" content="添加群成员" placement="bottom-end">
              <i class="el-icon-circle-plus-outline btn-add-member" @click="addGroupMember" />
            </el-tooltip>

            <!-- <el-button circle size="mini" icon="el-icon-plus" @click="addGroupMember"></el-button> -->
          </div>

        </slot>
      </div>
      <chat-box
        :list=" [...(messageListMap[uistate.chatid]||[])].splice(0,20).reverse() "
        :chatType="chatMap[uistate.chatid] && chatMap[uistate.chatid].type == 1 ? 'user' : 'group'"
        :isOwner="chatMap[uistate.chatid] && chatMap[uistate.chatid].isfirst == 1"
        @groupReply="groupReply"
        @atUser="atUser"
        @deleteUser="deleteUser"
        @openHistoryDialog="openHistoryDialog"
        @addFriend="addFriend"
        @repeat="repeatMessage"
        >
      </chat-box>
      <div class="messageTools flex-row">
        <div class="emojiContainer flex-row" v-show="showEmoji">
          <div v-for="(emoji, i) in emojis" :key="i" class="face" @click.prevent="chooseEmoji(emoji)">
            <img :src="emoji.img" alt="">
          </div>
        </div>
        <div class="tools">
          <i class="sendEmoji toolsIcon" @click="toggleEmojiContainer"></i>
          <i class="sendFile toolsIcon"><input type="file" @change="fileChange($event)"></i>
          <i class="findHistory toolsIcon" @click="openHistoryDialog"></i>
        </div>
        <button class="invite layui-btn layui-btn-xs" @click="openInviteDialog" v-if="!isGroup">邀请进群</button>
      </div>
      <div class="textContainer flex-column" :style="{ 'background':chatid === -1?'#f1f1f1':''  }">
        <div :contenteditable="chatid!==-1" ref="editor" class="textBox autoGrow"
          @input="textInput"
          @keypress="editorPress"
          @keydown="editorDown"
          @paste="textPaste"
        ></div>
        <button class="sendMessage layui-btn layui-btn-xs" @click="sendMessage">发送</button>
      </div>
    </div>
    <user-info v-if="tab==='messageList'"></user-info>
    <div v-if="showFriendFloat" class="friend" :style="this.floatCoords">
      <div class="sc-view" ref="scView">
        <ul ref="floatFriendList">
          <template v-for="(friend,index) in floatfriends">
          <li :class="['item', 'flex-row',index===floatIndex&&'active']" :key="index">
              <img :src=" (friend||{}).avatar" alt="" class="avatar">
              <div class="name flex-column"><span class="textEllipsis">{{(friend||{}).nick}}</span></div>
          </li>
          </template>
        </ul>
      </div>

      <div style="position: absolute;bottom: -10px;width: 20px;height: 20px;transform: rotate(45deg);background: #fff;left: 65px;"></div>
    </div>
    <dialogSelectFriend ref="dialogSelectFriend" />
    <dialogSelectGroup ref="dialogSelectGroup" />
    <dialogHistory :chat="chat" :account="account" :visible.sync="historyDrawer" @groupReply="groupReply" @atUser="atUser" />
  </div>
</template>

<script>
// @ is an alias to /src
import { mapState, mapActions, mapMutations } from 'vuex';
import dialogSelectFriend from '@/components/dialog-select-friend'
import dialogSelectGroup from '@/components/dialog-select-group'
import dialogHistory from '@/components/dialog-history'
import groupProfile from '@/views/service/group-profile'
import ChatBox from '@/components/chatBox';
import group from '@/components/group';
import friend from '@/components/friend';
import ServiceList from '@/views/service/serviceList';
import MessageList from '@/views/service/messageList';
import ChatList from '@/views/service/chatList';
import MessageItem from '@/components/messageItem'
import SystemMessage from '@/components/systemMessage'
import UserInfo from '@/views/service/userInfo';
import CustomDialog from '@/components/customDialog';
import UserListItem from '@/components/userListItem'
import { emotions } from '@/lib/wechat-emoji'
import { throttle ,getSelectionCoords,getEleCoords} from '@/lib/utils'
import pinyin from '@/lib/pinyin'
import config from '@/config'

export default {
  name: 'home',
  data() {
    return {
      ws: null,
      showServiceList: true,
      showDialog: false,
      showEmoji: false,
      historyDrawer:false,
      dialogType: 'editServiceInfo',
      tab: 'messageList',
      currentFriend: {},
      friendDetail: {},
      form: {},
      emojis: emotions,
      lastSelection: null,
      historyType: 'all',
      chats: [],
      chatsHistory:[],
      historyFilterType:0,
      pageNo:1,
      chatsFetching:false,
      floatRect:{
        top:0,
        left:0,
      },
      floatIndex:0,
      showFriendFloat:false,
      atWords:'',
      atWxid:[],
      floatCoords:{} ,
      groups:[],
      groupListMap:{},
      inviteGroups:{},
      accoutsyncing:false,
      inviteGroupFilterWord:'',
      friendFilterWord:'',
      showCollapse:['group','user']
    }
  },
  components: {
    ChatBox,
    CustomDialog,
    MessageList,
    ServiceList,
    UserInfo,
    UserListItem,
    MessageItem,
    ChatList,
    SystemMessage,
    group,
    friend,
    dialogSelectFriend,
    dialogSelectGroup,
    dialogHistory,
    groupProfile
  },
  mounted() {
    document.addEventListener('selectionchange',()=>{
      const sel = window.getSelection();
      this.lastSelection = sel;
    })
    this.$element.on('tab(changeTab)', this.changeTab)
    window.addEventListener('resize',this.moveFloatFriend)

  },
  destroyed(){
    window.removeEventListener('resize',this.moveFloatFriend)
  },
  computed: {
    ...mapState([
      'services',
      'manager',
      'messages',
      'currentMessages',
      'currentService',
      'currentUser',
      'chatList',
      'friendList',
      'adminMap',
      'accountMap',
      'accountListMap',
      'friendMap',
      'friendListMap',
      'chatMap',
      'chatListMap',
      'messageMap',
      'messageListMap',
      'uistate',
      'groupMemberList',
      'groupMemberMap'
    ]),

    groupMember(){
      const chatid = this.uistate.chatid
      const chat = this.chatMap[chatid]||{}
      const { csid,wxaccount,friendwxid} = chat
      const key = csid+'_'+wxaccount+'_'+friendwxid;
      const groupMemberList = this.groupMemberList[key]||[]
      const groupMember = groupMemberList.map(id=>{
        const item = this.groupMemberMap[id]
        return {
          wxid:item.wxid,
          nick:item.nick,
          avatar:item.avatar
        }

      })
      return groupMember
    },
    accFriends(){
      // 单聊
      const friendListMap = this.friendListMap[this.uistate.accountid]
      const friendList = friendListMap.map(id=>{
        const item = this.friendMap[id]
        return {
          wxid:item.friendwxid,
          nick:item.friendnick,
          avatar:item.avatar
        }
      })
      return friendList
    },
    isGroup(){
      return (this.uistate.chatid+'').endsWith('@chatroom')
    },
    floatfriends(){
      const scView = this.$refs.scView
      const floatRect = this.floatRect
      this.$nextTick(()=>{
        if(!this.$refs.scView)return;
        const height = this.$refs.scView.offsetHeight
        this.floatCoords = {
        left:floatRect.left-150/2+'px',
        top:floatRect.top-height-13+'px'
        }
      })
      return this.floatDataFilter()
    },
    csid(){
      return this.uistate.adminid
    },
    chatid(){
      return this.uistate.chatid
    },
    chat(){
      return this.chatMap[this.uistate.chatid]
    },
    account(){
      return this.accountMap[this.uistate.accountid]
    },
    prefix(){
      const chat = this.chat ||{}
      const { csid,wxaccount,friendwxid } = chat
      const key = csid+'_'+wxaccount+'_'+friendwxid+'_'
      return key
    },
    isGroup(){
      return this.chat?this.chatid.endsWith('@chatroom'):false
    },
    inviteGroupList(){
      const keyword = pinyin.getFullChars(this.inviteGroupFilterWord).toLocaleLowerCase()

      return this.groups.filter(g=>{
        const chars = pinyin.getFullChars( g.groupname+g.groupno ).toLocaleLowerCase()
        return chars.indexOf(keyword)>=0
      });
    },
    historyFilter(){
      const historyFilterType = this.historyFilterType
      const messageMap = this.messageMap
      if(historyFilterType == 1){
        return this.chatsHistory.filter(id=>{
          let content = {}
          if(typeof messageMap[id].content === 'object'){
            content = messageMap[id].content
          }else{
            try {
              content = JSON.parse(messageMap[id].content)
            } catch (error) {
              content = {
                msgtype:1,
                content:messageMap[id].content
              }
            }
          }

          return  content.msgtype === 6
        })
      }
      if(historyFilterType == 2){
        return this.chatsHistory.filter(id=>{
          let content = {}
          if(typeof messageMap[id].content === 'object'){
            content = messageMap[id].content
          }else{
            try {
              content = JSON.parse(messageMap[id].content)
            } catch (error) {
              content = {
                msgtype:1,
                content:messageMap[id].content
              }
            }
          }
          return  content.msgtype === 2 || content.msgtype === 4
        })
      }
      if(historyFilterType == 3){
        return this.chatsHistory.filter(id=>{
          let content = {}
          if(typeof messageMap[id].content === 'object'){
            content = messageMap[id].content
          }else{
            try {
              content = JSON.parse(messageMap[id].content)
            } catch (error) {
              content = {
                msgtype:1,
                content:messageMap[id].content
              }
            }
          }
          return  content.msgtype === 10
        })
      }
      return this.chatsHistory
    },
    friendFilterList(){
      const friendFilterWord = pinyin.getFullChars(this.friendFilterWord).toLocaleLowerCase()
      const friends = this.friendListMap[this.uistate.accountid]
      const friendMap = this.friendMap
      if( !friends )return []
      return friends.filter(id=>{
        const friend = friendMap[id]
        if(!friend)return false
        if(friend.isbrand||friend.isent)return false
        const chars = pinyin.getFullChars(friend.friendnick+friend.friendwxid).toLocaleLowerCase()
        return chars.indexOf(friendFilterWord)>-1
      })
    },
    groupFilterList(){
      if(!this.account)return [];

      const friendFilterWord = pinyin.getFullChars(this.friendFilterWord).toLocaleLowerCase()
      const groups = this.groupListMap[this.account.wxid]
      if( !groups )return []
      return groups.filter(group=>{
        if(!group)return false
        const chars = pinyin.getFullChars(group.groupname).toLocaleLowerCase()
        return chars.indexOf(friendFilterWord)>-1
      })
    },

  },
  watch: {
    messageListMap(newchatMap,oldchatMap){
      const { chatid } = this.uistate
      if(chatid!=-1){
        if(this.messageListMap[chatid])
          this.chatsHistory = [...this.messageListMap[chatid]]
      }else{
        this.chatsHistory = []
      }
      //
    },
    uistate(newuistate,olduistate){
      if(newuistate.chatid != olduistate.chatid){
        if(this.showDialog)this.openHistoryDialog()
        if(this.$refs.editor)this.$refs.editor.innerHTML=''
        this.showEmoji = false
      }
      if(newuistate.accountid!==olduistate.accountid){
        this.accoutsyncing = false;
        this.friendFilterWord = ''
      }

      this.$element.tabChange('changeTab', 'message')

    },
    chatList(chatList,oldchatList){
      const params = chatList.params
      const accountWxId = this.currentService.wxid;
      const friendWxid =this.currentUser.wxid;
      const csId = this.currentService.csid;

    },
    'chatList.list'(list){
      this.chats = [...list].splice(-20)
    },
    currentService(service, oldService = {}) {
      return;
      if (service && service.wxid != oldService.wxid) {
        const { csid, wxid } = service
        const messages = this.messages[this.currentService.wxid]
        if (messages) {
          return this.setCurrentMessages({
            messages,
            wxaccount: this.currentService.wxid
          })
        }
        this.initGroups({
          csid,
          wxaccount: wxid
        }).catch(e=>this.$msg(e));

        this.getFriendList({
          csid,
          wxaccount: wxid
        }).catch(e=>this.$msg(e));


      }
    },
    currentUser(friend={},oldfriend = {}){
      if(friend.wxid !== oldfriend.wxid){
        const { csid, wxid } = this.currentService
        const params = {
          accountWxId:wxid,
          friendWxid:friend.wxid,
          csId:csid,pageNo:this.pageNo,pageSize:20 }
        // { friendWxid:1,csId:1,pageNo:0,pageSize:100 }
        this.getChatList(params)
        this.pageNo = 1
        this.showDialog = false
      }
    },

  },
  methods: {

    ...mapActions(['initGroups','wsSend','getChatList','getFriendList','addChatByFriend','requestMessageMap','setStatus','setVIP']),
    ...mapMutations(['changeMessageInfo',
    'setCurrentMessages','addMessage',
    'setCurrentUser','addMessageListMap','addMessageMap',
    'updateUIState'
    ]),
    historyHandleClose(done){ done()},
    historyFilterChange(value){
      this.historyFilterType = value
    },
    floatDataFilter(name){
      const chatid = this.uistate.chatid
      const chat = this.chatMap[chatid]||{}
      const { csid,wxaccount,friendwxid} = chat
      const friendid = chat.friendwxid
      const isGroup = this.isGroup

      const friends = isGroup?this.groupMember:this.accFriends
      let floatfriends = []
      name = name || this.atWords
      if(friends.length){
        const wordspinyin = pinyin.getFullChars(name).toLocaleLowerCase()
        friends.forEach(friend=>{
          const fullchar = pinyin.getFullChars(friend.wxid+friend.nick).toLocaleLowerCase()
          if(fullchar.indexOf(wordspinyin)>-1){
            floatfriends.push( friend )
          }
        })
        if(!floatfriends[0]){
          this.showFriendFloat = false
        }
      }
      return floatfriends
    },
    changeTab(tab) {
      this.tab = tab.index === 0 ? 'messageList' : 'addressBook'
      if(tab.index===1){
        this.getGroupByWxid({
          csid:this.csid,
          wxid: this.account.wxid
        }).catch(e=>this.$msg(e));
      }
    },
    sendMessage() {
      if(!this.account.isonline){
        return this.$message({
                    showClose: true,
                    message: '设备离线,无法发送',
                    type: 'error'
                });
      }
      this.atWxid = []
      const contentArr = this.walkChildNodes(this.$refs.editor.childNodes);
      if(this.uistate.adminid>0 && this.uistate.child>0 && !content)return;
      const atStr = Array.from(new Set(this.atWxid)).join(',')
      contentArr.filter(item=>item.content||item.src).forEach((item,index,)=>{
        if(item.content.indexOf('@')>-1){
          item.wxid = atStr
        }
        const msgId = +Date.now()+index
        const msg = {
          wxAccount: this.accountMap[this.uistate.accountid].wxid,
          msgId,
          msgid:msgId,
          friendId: this.chatMap[this.uistate.chatid].friendwxid,
          msgType: 1,
          msgtype: 1,
          opType: 1,
          content:JSON.stringify(item),
          chatfrom:1,
          sendstatus:-100,
          chatid:this.uistate.chatid
        }
        this.addMessageMap(msg)
        this.addMessageListMap(msg)
        this.wsSend(msg)
      })

      this.$refs.editor.innerHTML=''
    },
    sendFriendCard(friend){

      const msgid = +Date.now()
      const msgtype = 13
      const message = {
          src:friend.avatar,
          msgtype,
          wxid:friend.wxid,
          content:friend.nick,
          title:friend.nick
        }

      const wxAccount = this.accountMap[this.uistate.accountid].wxid
      const friendId = this.chatMap[this.uistate.chatid].friendwxid
      if(friend.wxid === friendId)return this.$msg('对方无法接收自己的名片')
      const msg = {
        wxAccount,
        msgId:msgid,
        msgid,
        friendId,
        msgType: msgtype,
        msgtype,
        opType: 1,
        content:JSON.stringify(message),
        chatfrom:1,
        sendstatus:-100,
        chatid:this.uistate.chatid
      }
      if(confirm('是否发送好友 '+friend.nick+' 的个人名片')){
        this.addMessageMap(msg)
        this.addMessageListMap(msg)
        this.wsSend(msg)
      }

    },
    walkChildNodes(childNodes) {
      let contentArr = []
      let content = ''
      Array.from(childNodes).map(child=>{
        let nodeName = child.nodeName
        let className = child.className
        if (nodeName=='#text') {
          content += child.nodeValue
        } else if (nodeName=='IMG' && className ==='emoji' ) {
          content += `[${child.alt}]`
        } else if(className ==='editor-image'){
          const type = +child.getAttribute('type')
          contentArr.push({
            msgtype:1,
            content
          })
          contentArr.push({
            msgtype:type,
            src:child.alt,
            content:child.alt
          })
          content=''
        }else if (nodeName=='DIV') {
          content += '\n'
          contentArr.push({
            msgtype:1,
            content
          })
          content = ''
          contentArr = contentArr.concat( this.walkChildNodes(child.childNodes) )
        } else if (nodeName=='SPAN'){
          const _wxid = child.getAttribute('wxid')
          if(_wxid)this.atWxid.push(_wxid)
          contentArr.push({
            msgtype:1,
            content
          })
          content = ''
          contentArr = contentArr.concat( this.walkChildNodes(child.childNodes) )
        } else if (nodeName=='BR') {
          content += '\n'
        }
      })
      contentArr.push({
        msgtype:1,
        content
      })

      let resultArr = []
      let resultText = ''
      contentArr.forEach(item=>{
        if(item.msgtype === 1){
          resultText += item.content
        }else{
          resultArr.push({
            content:resultText,
            msgtype:1
          })
          resultArr.push(item)
          resultText = ''
        }
      })
      resultArr.push({
        content:resultText,
        msgtype:1
      })

      return resultArr
    },
    showFriendInfo(friend){
      this.friendDetail = {}
      this.currentFriend = friend;
      this.$api.friend.getFriendDetail({wxaccount:this.currentFriend.wxaccount,
      friendwxid:this.currentFriend.friendwxid})
      .then(rs=>{
        this.friendDetail = rs
        // window.alert(this.friendDetail.groups[0].groupno)
      })
    },
    showGroupInfo(group){
      this.currentFriend = group;
    },
    addChat(friend){
      // friend.id = undefined
      if(friend.friendwxid){
        this.addChatByFriend({...friend,id:undefined}) // 添加到chat相关
      }else{
        let _friend = {
          csid:friend.csid,
          wxaccount:friend.wxaccount,
          friendnick:friend.groupname,
          friendNick:friend.groupname,
          friendwxid:friend.groupno,
          avatar:friend.avatar
        }
        this.addChatByFriend(_friend)
      }



      const chatid = this.chatListMap[this.uistate.accountid][0]
      this.updateUIState({ chatid }) // ui 选中
      this.$element.tabChange('changeTab', 'message')

    },
    editorDown(e){
      if(this.showFriendFloat){
        const floatFriendList = this.$refs['floatFriendList']
        const length = floatFriendList.childElementCount
        let dur = 0
        if(e.code.toLocaleLowerCase() == 'arrowdown'){
          e.preventDefault()
          if(length-1 === this.floatIndex){
            this.floatIndex = 0
          }else{
            this.floatIndex++
          }
          dur = 1
        }
        if(e.code.toLocaleLowerCase() == 'arrowup'){
          e.preventDefault()
          if( this.floatIndex === 0){
            this.floatIndex = length-1
          }else{
            this.floatIndex--
          }
        }
        this.$nextTick(()=>this.floatPositionIndex(dur) )
      }

    },
    floatPositionIndex(dur){
      const floatFriendList = this.$refs['floatFriendList']
      const active = floatFriendList.querySelector('.active')
      if(!active)return
      const scrollview = floatFriendList.parentElement;
      const svHeight = scrollview.offsetHeight
      const scTop = scrollview.scrollTop
      const acTop = active.offsetTop
      const acHeight = active.offsetHeight
      if(scTop + svHeight < acTop+acHeight || scTop > acTop){
          scrollview.scrollTo(0, dur? acTop + acHeight - svHeight :acTop )
      }
    },
    editorPress(e){
      if(e.code.toLocaleLowerCase() == 'enter'){
        e.preventDefault()
        if(this.showFriendFloat){
          this.getAtWords(e)
        }else{
          this.sendMessage()
        }
      }
      if(e.key === '@'){
        e.preventDefault()
        this.insertAt(e)
        this.textInput(e)
      }


    },
    textInput(e){
      this.moveFloatFriend(e)
      this.getAtWords(e)
      this.floatIndex = 0
    },
    insertAt(e){
        let selection = window.getSelection()
        let range = selection.getRangeAt(0)
        const atNode = document.createElement('span')
        atNode.innerHTML='@'
        range.setStart(range.endContainer, range.endOffset) // 设置开始插入位置
        range.insertNode(atNode) // 插入元素，node节点
        range.setEnd(range.endContainer, range.endOffset) // 设置结束位置
        selection.selectAllChildren(this.$refs.editor) //选择容器
        selection.collapse(atNode,1)
    },
    getAtFriend(range){
      const selection = document.getSelection()
      if(!this.floatfriends[this.floatIndex])return;
      if(!this.showFriendFloat)return;
      const friend = this.floatfriends[this.floatIndex]
      const node = range.endContainer
      if(node.nodeName === '#text'){
        range.selectNodeContents(node.parentElement)
      }
      const name = '@'+friend.nick+''
      const nextText = document.createElement('span')
      if(this.isGroup){
        range.endContainer.innerHTML = name
        range.endContainer.setAttribute('wxid',friend.wxid)
        nextText.innerHTML = '&nbsp;'
        range.endContainer.after(nextText)
        selection.collapse(nextText,1)
      }else{
        this.sendFriendCard(friend)
        range.endContainer.innerHTML = ''
      }
      this.showFriendFloat = false
      this.atWords=''
      this.floatIndex = 0
    },
    getAtWords(e = {}){
      const key = e.key||e.data
      const code = e.code?e.code.toLocaleLowerCase():undefined
      const selection = document.getSelection()
      const range = selection.getRangeAt(0)
      const {endContainer,endOffset} = range
      const text = endContainer.textContent||key||''
      if(text&&text.indexOf('@')>-1){
        const attext = text.substr(1,endOffset)
        if(key === ' ' || code == 'enter'){
          this.getAtFriend(range)
        }else{
          if(this.floatDataFilter(attext).length){
            this.showFriendFloat = true
          }
          this.atWords = attext
        }
      }else{
        this.showFriendFloat = false
      }
    },
    moveFloatFriend(e){
      const docBody = document.body;
      const docEle = document.documentElement;
      const coords = getSelectionCoords()
      this.floatRect.left = coords.x + Math.max(docEle.scrollLeft,docBody.scrollLeft) - docEle.clientLeft;
      this.floatRect.top = coords.y + Math.max(docEle.scrollTop, docBody.scrollTop) - docEle.clientTop;

    },
    atUser(message) {
      this.$refs.editor.focus()

      const atNode = document.createElement('span')
        atNode.innerHTML='@'+message.realFromNick
        atNode.setAttribute('wxid',message.realFromWxId)

      const sel = this.lastSelection || window.getSelection();
      const range = sel.getRangeAt(0);
      range.setStart(sel.focusNode, sel.focusOffset)
      range.insertNode(atNode)
      range.selectNodeContents(this.$refs.editor)

      range.selectNodeContents(atNode)
      const node =  range.endContainer

      if(node.nodeName === '#text'){
        range.selectNodeContents(node.parentElement)
      }
      const nextText = document.createElement('span')
      nextText.innerHTML = '&nbsp;'
      range.endContainer.after(nextText)
      range.collapse()
      sel.collapse(nextText,1)
    },
    deleteUser(chat) {
      const index = this.$confirm(`确定踢出 ${chat.realFromNick}?`, {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(rs=>{
        this.confirmDeleteUser(chat)
      }).catch(e=>{
        console.log(e)
      })
    },

    confirmDeleteUser(chat) {
      const { csid,wxaccount,friendwxid,realFromWxId } = chat
      this.$api.group.removeGroupMember({
        csId :csid,
        accountWxId: wxaccount,
        groupNo: friendwxid,
        memberWxId: realFromWxId
      }).then(e=>{
        this.$message({
          message:'任务提交成功',
          type:'success'
        })
      }).catch(e=>this.$msg(e))

    },

    addFriend(user) {
      this.$prompt('添加群成员 '+user.realFromNick+' 为好友？', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          inputValue:'你好'
      }).then(({ value }) => {
          const applyMsg = value
          if(applyMsg === null) return;
          const param = {
              memberWxId:user.realFromWxId,
              groupNo:user.friendwxid,
              wxAccount:user.wxaccount,
              applyMsg,
              opType:3
          }
          this.wsSend(param)
      }).catch(() => {

      });

    },
    repeatMessage(message){
      if(!this.account.isonline){
        return this.$message({
                    showClose: true,
                    message: '设备离线,无法发送',
                    type: 'error'
                });
      }
      const msgId = message.msgid
      const msg = {
        wxAccount: message.wxaccount,
        msgId,
        msgid:msgId,
        friendId: message.friendwxid,
        msgType: message.msgtype,
        msgtype: message.msgtype,
        opType: 1,
        content:JSON.stringify(message.content),
        chatfrom:1,
        sendstatus:-100,
        id:message.id
      }
      this.wsSend(msg)

    },
    groupReply(chat) {
      this.historyDrawer = false
      this.$refs.editor.focus()
      const sel = this.lastSelection || window.getSelection();
      const range = document.createRange();
      range.selectNodeContents(this.$refs.editor)
      range.collapse()
      sel.removeAllRanges();
      sel.addRange(range);
    },
    chooseEmoji(item) {
      const src = item.img
      this.showEmoji = false
      const sel = this.lastSelection || window.getSelection();
      const range = document.createRange();
      const el = document.createElement("img");
      el.src = src;
      el.alt = item.text
      el.classList.add('emoji')
      if (this.lastSelection) {
        this.$refs.editor.focus()
        range.setStart(sel.focusNode, sel.focusOffset)
        document.execCommand('insertHTML', false, `${el.outerHTML}`)
        return
      }
      this.$refs.editor.appendChild(el)
      this.$refs.editor.focus()
      range.selectNodeContents(this.$refs.editor)
      range.collapse()
      sel.removeAllRanges();
      sel.addRange(range);
    },
    toggleEmojiContainer( ) {
      this.showEmoji = !this.showEmoji
    },

    sendFile(res,file={}){
      let type
      if(res.endsWith('.mp4')){
        type = 4 // 视频
      }else{
        type = 6 // 文件
      }
      const msgId = +Date.now()
      const content = {
        msgtype:type,
        title:file.name||res,
        content:file.name||res,
        src:res
      }
      const msg = {
        wxAccount: this.accountMap[this.uistate.accountid].wxid,
        msgId,
        msgid:msgId,
        friendId: this.chatMap[this.uistate.chatid].friendwxid,
        friendwxid:this.chatMap[this.uistate.chatid].friendwxid,
        msgType: 1,
        msgtype: 1,
        opType: 1,
        content:JSON.stringify(content),
        chatfrom:1,
        sendstatus:-100,
        // wxid:'TonitEcslipse',
        chatid:this.uistate.chatid
      }
      console.log(msg)
      this.addMessageMap(msg)
      this.addMessageListMap(msg)
      this.wsSend(msg)

    },
    async fileChange(e) {
      const file = e.target.files[0]
      await this._fileChange(file)
      if(e.target){ // 清除文件选择
        e.target.value = ''
      }
    },
    async _fileChange(file){
      if (file.size / 1000 / 1000 > 100 || file.size==0 ) {
          this.$message({
              message:'由于微信限制，文件需要大于0M且小于100M',
              type:'error'
          })
          return undefined
      }
      let res
      try {
        res = await this.uploadFile(file,{})
      } catch (error) {
        return
      }
      if(res){
        let type
        if( res.endsWith('.png')||res.endsWith('.jpg')||res.endsWith('.gif')||res.endsWith('.jpeg') ){
          type = 2
        }else{
          let allow = confirm('是否确定发送 '+( file.name||res ) +' 给好友')
          if(allow)this.sendFile(res,file)
          return
        }
        const sel = this.lastSelection || window.getSelection();
        const range = document.createRange();
        const el = document.createElement("img");
        el.src = config.apiUrl+'/'+res;
        el.classList.add('editor-image')
        el.alt = res;
        el.setAttribute('type',type)
        el.style.maxWidth = '250px'
        if (this.lastSelection) {
          this.$refs.editor.focus()
          range.setStart(sel.focusNode, sel.focusOffset)
          document.execCommand('insertHTML', false, `${el.outerHTML}`)
          return
        }
        this.$refs.editor.appendChild(el)
        this.$refs.editor.focus()
        range.selectNodeContents(this.$refs.editor)
        range.collapse()
        sel.removeAllRanges();
        sel.addRange(range);
      }
    },
    toggleServiceList: function(e) {
      this.showServiceList = !this.showServiceList;
    },
    changeUserVip(bool) {
      const chatid = this.uistate.chatid
      const chat = this.chatMap[this.uistate.chatid]
      if(!chat)return;
      const { csid,wxaccount,friendwxid,isTop } = chat
      const params = {type:this.isGroup?1:0 ,chatid,csId:csid, wxAccount:wxaccount, friendAccount:friendwxid,isTop:isTop===1?2:1}
      this.setVIP(params)
    },
    toggleMessageDecline() {
      const chatid = this.uistate.chatid
      const chat = this.chatMap[this.uistate.chatid]
      if(!chat)return;
      const { csid,wxaccount,friendwxid,showstatus } = chat
      const params = {chatid,csId:csid, wxAccount:wxaccount, friendAccount:friendwxid,showStatus:showstatus===0?1:0}
      this.setStatus(params)

      // this.changeMessageInfo({
      //   ...this.currentUser,
      //   decline: !this.currentUser.decline
      // });
    },
    async openInviteDialog(data) {
      const { csid,wxaccount,friendwxid,showstatus } = data||this.chat
      const members = this.groupMember
      const filterNos = []
      const initialNos = []

      const params = {
        csid,
        wxaccount,
        multiple:true,
        filterType:1,
        type:0,
        filterNos,
        initialNos,
        initialDisabled:true // 禁用
      }
      try {
        const rs = await this.$refs.dialogSelectGroup.getSelectFriendsAsync(params)
        const groupnos = rs.map(item=>item.groupno)
        const inviteParams = {
          wxAccount:wxaccount, csId:csid, friendWxid:friendwxid, groupNos:groupnos.join(',')
        }
        const inviteRs = this.$api.group.sendGroupInvite(inviteParams)
      } catch (error) {

      }


    },

    groupSelect(e){
      if(!e.target.value)return
      this.inviteGroups[e.target.value] = e.target.checked
    },
    changeForm(name, key, val, e) {
      let file, tempUrl;
      if (e && e.target && e.target.files) {
        file = e.target.files[0]
        tempUrl = window.URL.createObjectURL(file);
        return this.$set(this.form, name, {
          ...this.form[name],
          [key]: file,
          tempUrl
        })
      }
      this.$set(this.form, name, {
        ...this.form[name],
        [key]: val
      })
    },
    changeHistoryType(type) {
      this.historyType = type;
    },
    openHistoryDialog() {


      this.historyDrawer = true
      // this.showDialog = !this.showDialog;
      // this.dialogType = 'history'
    },


    async endreached(e){
      if(this.chatsFetching)return;
      const chatid = this.uistate.chatid
      const chat = this.chatMap[chatid]
      const { friendwxid,wxaccount,csid } = chat
      const params = {
          accountWxId:wxaccount,
          friendWxid:friendwxid,
          csId:csid,pageNo:this.pageNo+1,pageSize:20,chatid }
        // { friendWxid:1,csId:1,pageNo:0,pageSize:100 }
      try {
        const rs = await this.requestMessageMap(params)
        this.pageNo+=1
      } catch (error) {
        console.log(error)
      }
      this.chatsFetching = false
    },

    historyScroll:throttle(function(e){
      const scrollview = this.$refs['hiscrollview']
      const scroller = this.$refs['hiscroller']
      const { paddingTop,paddingBottom } = getComputedStyle(scrollview)

      if(scrollview.scrollTop+scrollview.offsetHeight+100 >= scroller.offsetHeight){
        this.endreached()
      }

    },200,{ leading:true }),

    getAvatar(message){
      const account = this.account;
      const chat = this.chat
      const prefix = this.prefix
      let src = ''

      if(+message.chatfrom===1){
        src = account.avatar
      }else if(+message.chatfrom===2){
        if( message.realFromWxId ){
          const groupMember = this.groupMemberMap[prefix+message.realFromWxId]||{}
          src = groupMember.avatar
        }else{
          src = chat.avatar
        }
      }

      return src
    },
    accountSync(){

      const account = this.accountMap[this.uistate.accountid]
      const csid = this.uistate.adminid
      const wxAccount = account.wxid
      const params = {wxAccount}
      this.$api.user.sync(params)
        .then(data=>{
          // this.accoutsyncing = true
          this.$msg('后台开始同步通讯录')
          window.friendSync = (wsdata)=>{
            const wxaccount = wsdata.wxAccount
            this.getFriendList({
              csid,
              wxaccount
            }).catch(e=>this.$msg(e));
            this.getGroupByWxid({
              csid,
              wxid:wxaccount
            }).catch(e=>this.$msg(e));
          }

        })
        .catch(e=>this.$msg(e))
    },
    textPaste(e){
      e.preventDefault()
      this._textPaste(e.clipboardData)
    },

    fileDrop(e){
      e.preventDefault()
      this._textPaste(e.dataTransfer)
    },
    _textPaste(dataTransfer){
      const file = Array.from(dataTransfer.files)[0]
      if(file){
        return this._fileChange(file)
      }
      const text = Array.from(dataTransfer.items)[0]
      if(text){
        text.getAsString((str)=>{
          let selection = window.getSelection()
          let range = selection.getRangeAt(0)
          const atNode = document.createElement('span')
          atNode.innerHTML=str
          range.setStart(range.endContainer, range.endOffset) // 设置开始插入位置
          range.insertNode(atNode) // 插入元素，node节点
          range.setEnd(range.endContainer, range.endOffset) // 设置结束位置
          selection.selectAllChildren(this.$refs.editor) //选择容器
          selection.collapse(atNode,1)
        })
      }
    },
    getGroupByWxid({csid,wxid}) {
      if(!csid || !wxid)return;
      return this.$api.group.list({
        csid,
        wxaccount:wxid
      }).then(rs=>{
        this.$set(this.groupListMap,wxid,rs)
      })
    },
    async addGroupMember(){
      const {csid,wxaccount,friendwxid} = this.chat
      const members = this.groupMember
      const filterWxids = members.map(item=>item.wxid)
      const selectFriends = await this.$refs.dialogSelectFriend.getSelectFriendsAsync({
        csid,
        wxaccount,
        multiple:true,
        filterType:1,
        type:1,
        filterWxids
      })
      if(selectFriends){
        this.$api.group.addFriend2Group({
          csId:csid, wxAccount:wxaccount, friendWxAccountList:selectFriends.map(item=>item.friendwxid) , groupNo:friendwxid
        }).then(rs=>{
          this.$message({
            type: 'success',
            message:'邀请成功'
          })
        })
      }
    }
  }
}
</script>

<style scoped>
.serviceContainer .chatContainer{
  word-break: break-all
}
.serviceContainer .chatContainer .textContainer .textBox{
    overflow: auto;
    word-break: break-all;
}
.serviceContainer /deep/ .textBox span[wxid]{
  color:#409eff
}
.serviceContainer .infoContainer{
  width: 300px;
  flex-shrink: 0;
}
.serviceContainer .serviceList{
  flex-shrink: 0;
}
.serviceContainer .userDetail{
  align-items: flex-start;
}
.serviceContainer .userDetail .sendMessage{
  margin: 0 auto;
}
.chat-column{
  width: 210px;
  border-right: 1px solid #ccc;
  flex-shrink: 0
}
.chat-column .layui-tab-title{
  justify-content: space-around
}
.serviceContainer .messageList{
  border:0;
  width: 100%;
}
.contacts-list >>> .el-collapse-item__header{
  background: transparent;
  height: 36px;
  line-height: 36px;
}
.contacts-list >>> .el-collapse-item__wrap{
  background: transparent
}
.contacts-list .contacts-list-item{
  cursor: default;
  box-sizing: border-box;
  justify-content: space-between;
  align-items: center;
  box-sizing: border-box;
  padding: 10px 10px 10px 20px
}
.contacts-list .contacts-list-item.active{
  background: #ccc;
}
.list-title{
  padding: 10px;
  font-size: 14px;
  color: #999;
}
.friend .active{
  background-color: #38dd60
}
.friend .active .name{
  color: #fff
}
.editor-image{
  max-width: 250px;
}
.friend{
  z-index:1000;
  background-color:#fff;
  width:150px;

  position: absolute;
  box-shadow: #333 0px 1px 10px 0px;
  border-radius:5px;
  padding: 2px;
}
.friend .sc-view{
  overflow:auto;height:100%;position: relative;z-index:1;border-radius:5px;
  max-height:165px;
}
.friend .item{
  padding: 3px;
  border-radius: 3px;
  overflow: hidden;
  justify-items: center;
  align-items: center;
}
.friend .item .avatar{
  width: 24px;
  height:24px;
  border-radius: 3px;
  flex-shrink: 0
}

.friend .name{
  margin-left: 5px;
  font-size: 13px;
  color: #333;
  overflow: hidden;
}

.messageTitle{
  background: #f2f2f2
}
.history-name{
  display: flex;
  color:#b4b1b1;font-size:12px;margin-bottom:5px;
}
.history-name.self{
  flex-direction: row-reverse;
}


.layui-tab-content{
  padding:10px 0
}

.chatOperate{
   padding: 0 10px;
}
.chatSearch{
  border: none
}
.chatTitle{
  padding:0 10px;
}
.clear{
  width: 30px;
  height: 30px;
  justify-content: center;
  align-items: center;
}
.clear .layui-icon{
  font-size: 20px;
  color: #999
}
.profile-group{
  display: flex;
  flex-direction: column;
  width: 380px;
  margin: 80px 0 32px 0;
  padding-bottom: 32px;
  justify-content: center;
  align-items: center;
}
.btn-add-member{
    font-size: 24px;
    display: block;
    line-height: 1;
    width: 28px;
    height: 28px;
    text-align: center;
    line-height: 28px;
    color: #01AAED
}


.history-dialog-drawer{

}
.history-dialog-drawer >>> .el-drawer__body{
  height:100%
}
.history-dialog-drawer >>> .history-dialog-drawer-main{
  display:flex;
  flex-direction: column;
  height:100%;
}

.label-width{
  width:150px !important
}

  /** 用户详情群及会员信息 **/
  .userDetail{
    overflow: hidden;
  }
  .vip-group{
    overflow: hidden;

    display: flex;
    height: 100%;
    flex: 1;
    margin-left: 32px;
    padding: 32px;
    box-sizing: border-box;
    border-left: 1px solid #dddddd;
  }
  .vip-group .caption{

    border-bottom: 1px solid #dddddd;
  }
  .vip-group .caption .th div{
    font-size: 14px;
    text-align: left;
    white-space: nowrap;
    color: #909399;
    font-weight: 400;
    padding: 15px;
    line-height: 1.5em;
  }
  .vip-group .title{
    display: flex;
    flex-direction: row;
    align-items: center;
    font-size: 18px;
  }
  .vip-group .btn-add-group{
    margin-left: 20px;
  }
  .vip-group-scroll{
    display: flex;
    height: 100%;
    flex: 1;
    overflow-y: auto;
    flex-direction: column;
  }
  .vip-group-scroll .tr{
    display: flex;
    flex-direction: row;
    border-bottom: 1px solid #dcdfe6;
  }
  .vip-group-scroll .td{
    font-size: 14px;
    text-align: left;
    white-space: nowrap;
    color: #909399;
    font-weight: 400;
    padding: 15px;
    line-height: 28px;
  }
  .vip-group-name{
    flex: 1;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .vip-group-isvip{
    width: 120px;
    flex-shrink: 0;
  }
  .vip-group-ctrl{
    width: 120px;
    flex-shrink: 0;
  }
</style>
